/*! \file uart.c \brief UART driver with buffer support. */
// *****************************************************************************
//
// File Name	: 'uart.c'
// Title		: UART driver with buffer support
// Author		: Pascal Stang - Copyright (C) 2000-2002
// Created		: 11/22/2000
// Revised		: 06/09/2003
// Version		: 1.3
// Target MCU	: ATMEL AVR Series
// Editor Tabs	: 4
//
// This code is distributed under the GNU Public License
//		which can be found at http://www.gnu.org/licenses/gpl.txt
//
// *****************************************************************************

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>


#include "uart.h"

// UART global variables

/** Pointer to the String to be transmited on the SCI interface.
*   It should be 'NULL' terminated.
*/
static u8  * pu8TxDataPointer;

/** Local Counter for the transmitter buffer.
*/
static u8  u8DataCounter;

/** Internal flag to indicate of presence of data to be sent.
*/
static TYP_tu8Bool bDataPresent;

volatile u08   uartBufferedTx;		///< uartBufferedTx flag
// receive and transmit buffers
BUF_tstrBuffer uartRxBuffer;				///< uart receive buffer

unsigned short uartRxOverflow;		///< receive overflow counter

#ifndef UART_BUFFERS_EXTERNAL_RAM
	// using internal ram,
	// automatically allocate space in ram for each buffer
	static char uartRxData[UART_RX_BUFFER_SIZE];
	
#endif

typedef void (*voidFuncPtru08)(unsigned char);
volatile static voidFuncPtru08 UartRxFunc;

// enable and initialize the uart
void uartInit(void)
{
	// initialize the buffers
	uartInitBuffers();
	// initialize user receive handler
	UartRxFunc = 0;

	// enable RxD/TxD and interrupts
	outb(UCR, BV(RXCIE)|BV(TXCIE)|BV(RXEN)|BV(TXEN));

	// set default baud rate
	uartSetBaudRate(UART_DEFAULT_BAUD_RATE);  
	// initialize states
	
	uartBufferedTx = FALSE;
	// clear overflow count
	uartRxOverflow = 0;

	pu8TxDataPointer = (u8 *)0;
    
    u8DataCounter = TYP_u8ZERO;
    
    bDataPresent = TYP_u8FALSE;
    
	// enable interrupts
	sei();
}

// create and initialize the uart transmit and receive buffers
void uartInitBuffers(void)
{
	#ifndef UART_BUFFERS_EXTERNAL_RAM
		// initialize the UART receive buffer
		BUF_vidInit(&uartRxBuffer, uartRxData, UART_RX_BUFFER_SIZE);
		
		
	#else
		// initialize the UART receive buffer
		BUF_vidInit(&uartRxBuffer, (u08*) UART_RX_BUFFER_ADDR, UART_RX_BUFFER_SIZE);
		
		
	#endif
}

// redirects received data to a user function
void uartSetRxHandler(void (*rx_func)(unsigned char c))
{
	// set the receive interrupt to run the supplied user function
	UartRxFunc = rx_func;
}

// set the uart baud rate
void uartSetBaudRate(u32 baudrate)
{
	// calculate division factor for requested baud rate, and set it
	u16 bauddiv = ((F_CPU+(baudrate*8L))/(baudrate*16L)-1);
	outb(UBRRL, bauddiv);
	#ifdef UBRRH
	outb(UBRRH, bauddiv>>8);
	#endif
}

// returns the receive buffer structure 
BUF_tstrBuffer* uartGetRxBuffer(void)
{
	// return rx buffer pointer
	return &uartRxBuffer;
}



// transmits a byte over the uart
TYP_tu8Bool URT_bSendByte(u8 u8Data)
{

	TYP_tu8Bool bReturnValue;
	u8 u8TxcTemp;
	
	u8TxcTemp = ((UCSRA & (1<<TXC)) >> TXC);
    
    if (u8TxcTemp == TYP_u8ZERO)
    {
		UCSRA |= (1<<TXC);
        UDR = u8Data;
        bReturnValue = TYP_u8TRUE;
    }
    else
    {
        bReturnValue = TYP_u8FALSE;
    }
    return bReturnValue;
}

TYP_tu8Bool URT_bSendString(u8 au8Data[])
{
    TYP_tu8Bool bReturnResult;
    
    if (bDataPresent == TYP_u8FALSE)
    {
        pu8TxDataPointer  =   (u8 *)au8Data;
        bDataPresent    =   TYP_u8TRUE;
        bReturnResult   =   TYP_u8TRUE;
    }
    else
    {
        bReturnResult   =   TYP_u8FALSE;
    }
    
    return bReturnResult;
}

void URT_vidMainFunction(void)
{
    TYP_tu8Bool bTempResult;
    u8          u8TempData;
    if ( bDataPresent == TYP_u8TRUE)
    {
        u8TempData = pu8TxDataPointer[u8DataCounter];
        if ( u8TempData != '\0' )
        {
            bTempResult = URT_bSendByte(u8TempData);
            if (bTempResult == TYP_u8TRUE)
            {
                 u8DataCounter++;
                 if (u8DataCounter == (u8)255)
                 {
                    bDataPresent = TYP_u8FALSE;
                    u8DataCounter = TYP_u8ZERO;
                 }
            }
        }
        else
        {
            u8DataCounter = TYP_u8ZERO;
            bDataPresent = TYP_u8FALSE;
        }
        
        
    }
}

// gets a single byte from the uart receive buffer (getchar-style)
int uartGetByte(void)
{
	u08 c;
	if(uartReceiveByte(&c))
		return c;
	else
		return -1;
}

// gets a byte (if available) from the uart receive buffer
u08 uartReceiveByte(u08* rxData)
{
	// make sure we have a receive buffer
	if(uartRxBuffer.u16Size)
	{
		// make sure we have data
		if(uartRxBuffer.u16DataLength)
		{
			// get byte from beginning of buffer
			*rxData = BUF_u8GetFromFront(&uartRxBuffer);
			return TRUE;
		}
		else
		{
			// no data
			return FALSE;
		}
	}
	else
	{
		// no buffer
		return FALSE;
	}
}

// flush all data out of the receive buffer
void uartFlushReceiveBuffer(void)
{
	// flush all data from receive buffer
	//bufferFlush(&uartRxBuffer);
	// same effect as above
	uartRxBuffer.u16DataLength = 0;
}

// return true if uart receive buffer is empty
u08 uartReceiveBufferIsEmpty(void)
{
	if(uartRxBuffer.u16DataLength == 0)
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}





// UART Receive Complete Interrupt Handler
UART_INTERRUPT_HANDLER(SIG_UART_RECV)
{
	u08 c;
	
	// get received char
	c = inb(UDR);

	// if there's a user function to handle this receive event
	if(UartRxFunc)
	{
		// call it and pass the received data
		UartRxFunc(c);
	}
	else
	{
		// otherwise do default processing
		// put received char in buffer
		// check if there's space
		if( !BUF_u8AddToEnd(&uartRxBuffer, c) )
		{
			// no space in buffer
			// count overflow
			uartRxOverflow++;
		}
	}
}
